package io.gitee.yxsnake.embark.redis.configuration;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Preconditions;
import io.gitee.yxsnake.embark.redis.common.RedisConstants;
import io.gitee.yxsnake.embark.redis.configuration.properties.CustomCacheProperties;
import io.gitee.yxsnake.embark.redis.serializer.StringRedisSerializer;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.hutool.core.text.StrUtil;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;


/**
 * @author snake
 * @description 目的：使用自己定义的 RedisTemplate Bean
 * @since 2024/10/27 11:57
 */
@Slf4j
@AutoConfigureBefore(value = {RedisAutoConfiguration.class})
@RequiredArgsConstructor
@Import({CustomCacheProperties.class})
public class CustomRedisAutoConfiguration {

    private final Environment environment;

    private final CustomCacheProperties customCacheProperties;

    private final RedisProperties redisProperties;

    /**
     * 验证规则 <br> 默认加载 redis.biz-prefix <br> 如果该参数为空则加载 spring.application.name <br>
     * 如果二者都为空，抛出异常启动终止
     */
    @PostConstruct
    public void init() {
        validRequiredParams();
        log.info("------------ embark-data-redis-starter info -----------");
        log.info("redis-starter");
        log.info("    |-host: {}",redisProperties.getHost());
        log.info("    |-port: {}", redisProperties.getPort());
        log.info("    |-password: {}", redisProperties.getPassword());
        log.info("-------------------------------------------------------------");
    }

    /**
     * 自定义序列化
     *
     * @param redisConnectionFactory
     * @return
     */
    @Bean
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {

        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);

        // 设置objectMapper:转换java对象的时候使用
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(objectMapper, Object.class);
        String prefix = StrUtil.isBlank(customCacheProperties.getBizPrefix()) ? "" : customCacheProperties.getBizPrefix() + RedisConstants.BIZ_PREFIX_SPLIT;
        log.info("biz-prefix > {}", prefix);

        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(prefix);

        // 设置key/value值的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        template.setValueSerializer(jackson2JsonRedisSerializer);
        template.setHashKeySerializer(stringRedisSerializer);
        template.setHashValueSerializer(jackson2JsonRedisSerializer);

        template.afterPropertiesSet();
        return template;
    }




    /**
     * 默认加载 redis.biz-prefix, 如果该参数为空则加载 spring.application.name, 如果二者都为空，抛出异常启动终止
     */
    private void validRequiredParams() {
        String applicationName = getApplicationName();
        if (StrUtil.isBlank(applicationName)) {
            Preconditions.checkArgument(StrUtil.isNotBlank(customCacheProperties.getBizPrefix()),
                    "Missing required configuration items: redis.biz-prefix");
        } else {
            if (StrUtil.isBlank(customCacheProperties.getBizPrefix())) {
                customCacheProperties.setBizPrefix(applicationName);
                log.info(
                        "The configuration item (redis.biz-prefix) is missing, using the default value > {} (spring.application.name)",
                        applicationName);
            }
        }
    }

    private String getApplicationName(){
        return environment.getProperty("spring.application.name");
    }
}
